﻿#include<iostream>
#include<graphics.h>
#include<vector>
#include<conio.h>

using namespace std;

constexpr auto swidth = 600;
constexpr auto sheight = 1100;

//开始界面中用到的鼠标位置判断函数，在r这个矩形中才返回1
bool PointInRect(int x, int y, RECT& r) 
{
	return(r.left <= x && x <= r.right && r.top <= y && r.bottom >= y);
}

//矩形相撞算法
bool RectDuangRect(RECT& r1, RECT& r2)
{
	RECT r;
	r.left = r1.left - (r2.right - r2.left);
	r.right = r1.right;
	r.top = r1.top - (r2.bottom - r2.top);
	r.bottom = r1.bottom;

	return (r.left < r2.left && r2.left <= r.right && r.top <= r2.top && r2.top <= r.bottom);
}

//开始界面
void Welcome() 
{
	//在画布上显示文字
	LPCTSTR title = _T("飞坤大战");
	LPCTSTR tplay = _T("开始铁山靠");
	LPCTSTR texit = _T("退出篮球");

	RECT tplayr, texitr;

	BeginBatchDraw();//开始批量绘画
	setbkcolor(WHITE);//白色背景
	cleardevice();
	settextstyle(60, 0, _T("黑体"));//这个函数用于设置当前文字样式，这里设置标题位置。
	settextcolor(BLACK);//黑色字体
	outtextxy(swidth / 2 - textwidth(title) / 2, sheight / 5, title);//这个函数用于在指定位置输出字符串，也就是文字出现位置。

	settextstyle(40, 0, _T("黑体"));//设定“开始”和“结束”的位置
	//tplayr这里是个结构体，包含两个点坐标，一个左上角一个右下角，刚好确定一个矩形框
	tplayr.left = swidth / 2 - textwidth(tplay) / 2;
	tplayr.right = tplayr.left + textwidth(tplay);
	tplayr.top = sheight / 5 * 2.5;
	tplayr.bottom = tplayr.top + textheight(tplay);
	//这段同样
	texitr.left = swidth / 2 - textwidth(texit) / 2;
	texitr.right = texitr.left + textwidth(texit);
	texitr.top = sheight / 5 * 3;
	texitr.bottom = texitr.top + textheight(texit);

	outtextxy(tplayr.left, tplayr.top, tplay);
	outtextxy(texitr.left, texitr.top, texit);

	EndBatchDraw();//结束批量绘画

	//以下是鼠标操作代码
	while (true) 
	{
		ExMessage mess;//保存鼠标消息，mess.x和.y就是鼠标点击位置
		getmessage(&mess, EM_MOUSE);//这个函数用于获取一个消息。如果当前消息队列中没有，就一直等待。函数里面是关于鼠标操作的代码。
		if (mess.lbutton) 
		{
			if(PointInRect(mess.x,mess.y,tplayr))
			{
				return;
			}
			else if (PointInRect(mess.x, mess.y, texitr))
			{
				exit(0);
			}
		}
	}
}

//结束界面
void Over(unsigned long long &kill) 
{	//我觉得可以搞个if，按击杀数来给结算词
	TCHAR* str = new TCHAR[128];
	_stprintf_s(str, 128, _T("击杀数：%llu"), kill);

	settextcolor(RED);
	outtextxy(swidth / 2 - textwidth(str) / 2, sheight / 5, str);//输出字符用的函数

	//键盘事件演示（按回车返回），用来显示这个提示
	LPCTSTR info = _T("按回车键返回");
	settextstyle(20, 0, _T("黑体"));
	outtextxy((swidth - textwidth(info)) / 2, (sheight - textheight(info)) / 2, info);

	while (true) 
	{
		ExMessage mess;
		getmessage(&mess, EM_KEY);
		if (mess.vkcode == 0x0D) 
		{
			return;
		}
	}

}

//各对象的类 背景，小黑子，鸡哥，篮球
class BK 
{
public:
	BK(IMAGE& img) 
		:img(img),y(-sheight)
	{

	}
	void Show() //不想让背景动就把这个函数注释了
	{
		if (y == 0)
		{
			y = -sheight;
		}
		y += 4;//加上的数一定要是屏幕高度的倍数（这里是上下滚动所以是高度y的倍数）
		putimage(0, y, &img);
	}
	int GetY() { return y; }
private:
	IMAGE& img;
	int x, y;
};

class kun 
{
public:
	kun(IMAGE& img) 
		:img(img)
	{	
		//初始化坤坤的矩形框
		rect.left = swidth / 2 - img.getwidth() / 2;
		rect.top = sheight - img.getheight();
		rect.right = rect.left + img.getwidth();
		rect.bottom = sheight;
	}

	void Show()
	{
		putimage(rect.left, rect.top, &img);
	}

	void Control()   //控制函数，既可用鼠标，也可用键盘,这一版用的是鼠标
	{
		//要用非阻塞函数，前面开始界面的那个是阻塞函数
		//是因为这里即使鲲鲲不动，小黑子也得动
		ExMessage mess;
		if (peekmessage(&mess, EM_MOUSE)) 
		{
			rect.left = mess.x - img.getwidth() / 2;
			rect.top = mess.y - img.getheight() / 2;
			rect.right = rect.right = rect.left + img.getwidth();
			rect.bottom = rect.top + img.getheight();
		}
	}
	RECT& GetRect() 
	{
		return rect;
	}

private:
	IMAGE& img;
	RECT rect;

};

class hei 
{
public:
	hei(IMAGE& img, int x)
		:img(img)
	{
		//黑子生成位置
		rect.left = x;
		rect.right = rect.left + img.getwidth();
		rect.top = -img.getheight();
		rect.bottom = 0;
	}

	bool Show() 
	{
		if (rect.top >= sheight) 
		{
			return false;
		}
		rect.top += 8;
		rect.bottom += 8;
		putimage(rect.left, rect.top, &img);
		return true;
	}

	RECT& GetRect()
	{
		return rect;
	}

	IMAGE& GetImg() { return img; }

private:
	IMAGE& img;
	RECT rect;

};

class qiu {
public:
	qiu(IMAGE& img,RECT pr) 
		:img(img) 
	{
		rect.left = pr.left + (pr.right - pr.left) / 2 - img.getheight() / 2;
		rect.right = rect.left + img.getwidth();
		rect.top = pr.top - img.getheight();
		rect.bottom = rect.top + img.getheight();
	}
	bool Show() 
	{
		if (rect.bottom <= 0) 
		{
			return false;
		}
		else 
		{
			rect.top -= 5;
			rect.bottom -= 5;
			putimage(rect.left, rect.top, &img);
			return true;
		}
	}

	RECT& GetRect()
	{
		return rect;
	}

	IMAGE& GetImg() { return img; }

protected:	
	IMAGE& img;
	RECT rect;

};

class EBullet :public qiu
{
public:
	EBullet(IMAGE& img,RECT pr)
		:qiu(img,pr)
	{
		rect.left = pr.left + (pr.right - pr.left) / 2 - img.getheight() / 2;
		rect.right = rect.left + img.getwidth();
		rect.top = pr.bottom;
		rect.bottom = rect.top + img.getheight();
	}
	bool Show()
	{
		if (rect.top >= sheight)
		{
			return false;
		}
		else
		{
			rect.top += 12;
			rect.bottom += 12;
			putimage(rect.left, rect.top, &img);
			return true;
		}
	}
};

//生成敌机函数
bool Addhei(vector<hei*>& hs, IMAGE& heiimg)
{
	hei* h = new hei(heiimg, abs(rand()) % (swidth - heiimg.getwidth()));
	for (auto& i : hs) 
	{
		if (RectDuangRect(i->GetRect(), h->GetRect())) 
		{
			delete h;
			return false;
		}
	}
	hs.push_back(h);
	return true;
}

//运行函数
bool Play()
{
	setbkcolor(WHITE);
	cleardevice();
	bool is_play = true;

	IMAGE kunimg, heiimg, bkimg, qiuimg;//插入图片
	IMAGE eboom1, eboom2, eboom3;
	//具体修图看视频第二期7分15秒左右那一段
	loadimage(&kunimg, _T("D:\\Users\\user\\Desktop\\u=3002285159,2036081077&fm=253&fmt=auto.png"),100,100);
	loadimage(&heiimg, _T("D:\\Users\\user\\Desktop\\u=2338631279,66661736&fm=253&fmt=auto&app=120&f=JPEG.png"),40,40);
	loadimage(&bkimg, _T("D:\\Users\\user\\Desktop\\89e9f0ab-a36d-47a4-91c7-86ebd1627612.png"), 0, 2200);
	loadimage(&qiuimg, _T("D:\\Users\\user\\Desktop\\src=http___cbu01.alicdn.com_img_ibank_2019_131_750_12712057131_1938888968.360x360.jpg&refer=http___cbu01.alicdn.png"),20,20);

	loadimage(&eboom1,_T(""));
	loadimage(&eboom2,_T(""));
	loadimage(&eboom3,_T(""));

	//生成背景和坤坤
	BK bk = BK(bkimg);
	kun hp = kun(kunimg);

	vector<hei*>hs;//这一段在生成敌机
	vector<qiu*>qs;//这一段在生成篮球
	vector<EBullet*>ebs;//这一段在生成敌机子弹
	int bsing = 0;
	int ebsing = 0;
	unsigned long long kill = 0;

	for (int i = 0; i < 5/*这个地方可以改场上的黑子数目*/; ++i)
	{
		Addhei(hs, heiimg);
	}

	while (is_play)
	{
		bsing++;//这几行用来调整射速
		if (bsing == 12) 
		{
			bsing = 0;
			qs.push_back(new qiu(qiuimg, hp.GetRect()));
		}

		ebsing++;
		if (ebsing == 60) 
		{
			ebsing = 0;
			for (auto& i : hs)
			{
				ebs.push_back(new EBullet(qiuimg, i->GetRect()));
			}
		}

		BeginBatchDraw();//开始批量绘画,防止屏闪

		bk.Show();//按这六行这样写，防止延迟，同时背景移动速度正常
		Sleep(6);

		flushmessage();
		Sleep(2);
		hp.Control();

		////这一坨是没用的暂停代码，要改
		//if (_kbhit()) 
		//{
		//	char v = _getch();
		//	if (v == 0X0D) 
		//	{
		//		Sleep(64);
		//		while (true) 
		//		{ 
		//			if (_kbhit()) 
		//			{
		//				v = _getch();
		//				if (v == 0X0D) 
		//				{
		//					break;
		//				}
		//			}
		//			Sleep(16);
		//		}

		//	}
		//}
		bool is_paused = false; // 新增暂停状态变量

		while (is_play) {
			// 处理键盘输入（替换原有暂停代码）
			ExMessage keyMsg;
			while (peekmessage(&keyMsg, EM_KEY)) {
				if (keyMsg.vkcode == VK_RETURN && keyMsg.message == WM_KEYDOWN) {
					is_paused = !is_paused;
				}
			}

			BeginBatchDraw();

			// 绘制背景（根据暂停状态判断是否更新）
			if (!is_paused) {
				bk.Show();
			}
			else {
				putimage(0, bk.GetY(), &bkimg);
			}

			// 非暂停状态下的更新逻辑
			if (!is_paused) {
				flushmessage();
				Sleep(2);
				hp.Control();

				// 原有子弹生成、敌机移动等更新逻辑
				bsing++;
				if (bsing == 12) { /* ... 生成子弹 ... */ }

				ebsing++;
				if (ebsing == 60) { /* ... 生成敌机子弹 ... */ }

				// 处理子弹移动
				auto qsit = qs.begin();
				while (qsit != qs.end()) {
					if (!(*qsit)->Show()) {
						// ... 移除无效子弹 ...
					}
					// ... 其他处理 ...
				}

				// 处理敌机移动和碰撞检测
				auto it = hs.begin();
				while (it != hs.end()) {
					// ... 原有敌机移动和碰撞处理 ...
				}

				// ... 其他非暂停状态下的更新 ...
			}
			else {
				// 暂停状态下手动绘制所有对象
				// 绘制子弹
				for (auto& q : qs) {
					putimage(q->GetRect().left, q->GetRect().top, &q->GetImg());
				}
				// 绘制敌机
				for (auto& h : hs) {
					putimage(h->GetRect().left, h->GetRect().top, &h->GetImg());
				}
				// 绘制敌机子弹
				for (auto& eb : ebs) {
					putimage(eb->GetRect().left, eb->GetRect().top, &eb->GetImg());
				}
				// 显示暂停提示
				settextcolor(RED);
				LPCTSTR pauseText = _T("暂停中，按回车继续");
				outtextxy(swidth / 2 - textwidth(pauseText) / 2, sheight / 2 - textheight(pauseText) / 2, pauseText);
			}

			// 绘制坤坤（无论是否暂停）
			hp.Show();

			EndBatchDraw();

			// ... 原有其他逻辑 ...
		}








		hp.Show();

		/*for (auto& i : qs) 
		{ 
			i->Show(); 
		}*/

		auto qsit = qs.begin();//这一段用来完成坤坤子弹飞出界面后的删除
		while (qsit != qs.end())
		{
			if (!(*qsit)->Show())
			{
				qsit = qs.erase(qsit);
			}
			else 
			{
				qsit++;
			}
		}

		auto ebsit = ebs.begin();//这一段用来完成敌机子弹飞出界面后的删除
		while (ebsit != ebs.end())
		{
			if (RectDuangRect((*ebsit)->GetRect(), hp.GetRect()))
			{
				is_play = false;
				break;
			}

			else if (!(*ebsit)->Show())
			{
				ebsit = ebs.erase(ebsit);
			}

			else
			{
				ebsit++;
			}
		}

		auto it = hs.begin();
		while (it != hs.end()) 
		{
			if(RectDuangRect((*it)->GetRect(),hp.GetRect()))
			{
				is_play = false;
			}
			auto qit = qs.begin();
			while (qit != qs.end()) 
			{
				if (RectDuangRect((*qit)->GetRect(), (*it)->GetRect())) 
				{
					delete(*it);
					hs.erase(it);
					it = hs.begin();
					delete (*qit);
					qs.erase(qit);

					kill++;//更新击杀数

					break;
				}
				qit++;
			}
			if (!(*it)->Show()) 
			{
				delete(*it);
				hs.erase(it);
				it = hs.begin();
			}
			else { it++; }
		}
		for (int i = 0; i < 5 - hs.size(); ++i) 
		{
			Addhei(hs, heiimg);
		}

		EndBatchDraw();
	}
	Over(kill);

	return true;
}

int main() 
{
	//这个函数用于绘制初始化窗口
	initgraph(swidth, sheight, EX_NOMINIMIZE | EX_SHOWCONSOLE);
	bool is_live = true;
	//接下来是游戏循环
	while (is_live) 
	{
		Welcome();
		
		is_live = Play();
	}

	return 0;
}